#include "defines.h"
#include "system.h"
#include "display.h"

#define TICKS_6_MS   6        // 0.006s * 1024 ticks/s

#define REL_TIMER_OFFSET 12  // Timer offset (overhead) for release builds.
#define DBG_TIMER_OFFSET 18  // Timer offset (overhead) for debug builds
///////////////////////////////////////////////////////////////////////////////
// Function:  StopWatchdog
// Purpose:   Disables the microcontroller's watchdog timer.
// Inputs:    None.
// Outputs:   None.
///////////////////////////////////////////////////////////////////////////////
void StopWatchdog(void)
{
	WDTCTL = WDTPW + WDTHOLD;
}
///////////////////////////////////////////////////////////////////////////////
// Function:  ConfigPorts
// Purpose:   Configures the microcontroller I/O ports.
// Inputs:    None.
// Outputs:   None.
// Notes:     Unused I/O are set to inputs with internal pulldown resistors.
///////////////////////////////////////////////////////////////////////////////
void ConfigPorts(void)
{
	// Configure Port 1 (OOOOOOOO)
	// Data bus to drivers.
	P1DIR = 0xff;
	P1REN = 0x00;
	P1OUT = 0x00;


	// Configure Port 2
	// RF interrupt
	// Configure Port 3 (IIIOIIII)
	
	// Configure Port 4 (IIIIIIII)
	// Set as RF and font
	
	// Configure Port 5 (IIIIIIII)
	// 5.2 as RF interrupt 2  5.3 RCLK
	P5DIR |= (RCLK + PL_EN + nEN_VDD);
	P5REN |= 0x00;
	P5OUT |= nEN_VDD;



	// Configure Port 6 (IOOOOIIO)
	P6DIR |= (nEN_3V + CCLK + ENABLE + EN_HV);
	
	P6REN |= 0x00;
	P6OUT |= (nEN_3V);

	PJDIR |= (PHASE_LONG + PHASE_SHORT + LATCH + TEMP);
	
	PJREN |= 0x00;
	PJOUT |= 0x00;

	//PJSEL = (TEMP);    // Enable TEMP pin for analog input.
}

void UnconfigPorts(void)
{
	// Configure Port 1 (OOOOOOOO)
	// Data bus to drivers.
	P1DIR = 0xff;
	P1REN = 0x00;
	P1OUT = 0x00;


	// Configure Port 2
	// RF interrupt
	// Configure Port 3 (IIIOIIII)
	
	// Configure Port 4 (IIIIIIII)
	// Set as RF and font
	
	// Configure Port 5 (IIIIIIII)
	// 5.2 as RF interrupt 2  5.3 RCLK
	P5DIR &= ~(RCLK + PL_EN + nEN_VDD);
	P5REN &= ~0x00;
	P5OUT &= ~nEN_VDD;



	// Configure Port 6 (IOOOOIIO)
	P6DIR &= ~(nEN_3V + CCLK + ENABLE + EN_HV);
	
	P6REN &= ~0x00;
	P6OUT &= ~(nEN_3V);

	PJDIR &= ~(PHASE_LONG + PHASE_SHORT + LATCH + TEMP);
	
	PJREN &= ~0x00;
	PJOUT &= ~0x00;

	//PJSEL = (TEMP);    // Enable TEMP pin for analog input.
}


///////////////////////////////////////////////////////////////////////////////
// Function:  ConfigClocks
// Purpose:   Configures clocking scheme and tunes internal oscillator to
//            the desired operating frequency.
// Inputs:    None.
// Outputs:   None.
// Notes:     None.
///////////////////////////////////////////////////////////////////////////////
void ConfigClocks()
{
    P5SEL |= BIT4 + BIT5;                       // Port select XT1
    
    // Set up XT1 Pins to analog function, and to lowest drive	
    UCSCTL6 &= ~(XT1OFF);                     // XT1 On
    UCSCTL6 |= XCAP_3;                        // Internal load cap   
    
    UCSCTL3 = SELREF_2;                       // Set DCO FLL reference = REFO
    UCSCTL4 |= SELA_2;                        // Set ACLK = REFO
    UCSCTL0 = 0x0000;                         // Set lowest possible DCOx, MODx
    
    // Loop until XT1,XT2 & DCO stabilizes - In this case only DCO has to stabilize
    do
    {
        UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG);
                                            // Clear XT2,XT1,DCO fault flags
        SFRIFG1 &= ~OFIFG;                      // Clear fault flags
    }while (SFRIFG1 & OFIFG);                   // Test oscillator fault flag
    
    __bis_SR_register(SCG0);                  // Disable the FLL control loop
    UCSCTL1 = DCORSEL_5;                      // Select DCO range 16MHz operation
    UCSCTL2 |= 249;                           // Set DCO Multiplier for 8MHz
                                            // (N + 1) * FLLRef = Fdco
                                            // (249 + 1) * 32768 = 8MHz
    __bic_SR_register(SCG0);                  // Enable the FLL control loop
    
    // Worst-case settling time for the DCO when the DCO range bits have been
    // changed is n x 32 x 32 x f_MCLK / f_FLL_reference. See UCS chapter in 5xx
    // UG for optimization.
    // 32 x 32 x 8 MHz / 32,768 Hz = 250000 = MCLK cycles for DCO to settle
    __delay_cycles(250000);
}

///////////////////////////////////////////////////////////////////////////////
// Function:  SetTimer
// Purpose:   Configures Timer to time a delay using SMCLK (DCO oscillator).
// Inputs:    ticks - duration to time (1 tick ~ 1 microsecond)
// Outputs:   None.
// Notes:     If using the built-in DCO calibration settings, the DCO has a
//            calibrated value of 1 MHz, with an overall tolerance of 0.95 MHz
//            to 1.05 MHz.
///////////////////////////////////////////////////////////////////////////////
void SetTimerMax(unsigned long ticks)
{
	unsigned int LowTicks;

	// Compute the partial TimerA period (16 bit counter) to time.
	LowTicks = ticks & 0xffff;

	// Enforce a minimum partial period to prepare for interrupt.
	LowTicks = (LowTicks >= 5 ? LowTicks : 5);

	// Compute the number of complete TimerA periods.
	gTimer = (ticks >> 16); // Global variable used in TACCR0 ISR.

	// Start the partial TimerA period.  
	TA1CTL &= ~(MC1 + MC0);   // Stop timer.
	TA1CTL = TASSEL0 + TACLR;  // SMCLK/8, no interrupt, clear divider.
	TA1CCR0 = LowTicks; // ~1x10^6 ticks/sec
	TA1CCTL0 = CCIE;          // Compare mode, flag cleared, interrupt enabled.
	TA1CTL |= MC1;            // Start timer in continuous mode.
}

///////////////////////////////////////////////////////////////////////////////
// Function:  SetTimer
// Purpose:   Configures Timer to time a delay using SMCLK (DCO oscillator).
// Inputs:    ticks - duration to time (1 tick ~ 1 microsecond)
// Outputs:   None.
// Notes:     If using the built-in DCO calibration settings, the DCO has a
//            calibrated value of 1 MHz, with an overall tolerance of 0.95 MHz
//            to 1.05 MHz.
///////////////////////////////////////////////////////////////////////////////
void SetTimer(unsigned long ticks)
{
	unsigned int LowTicks;
	
#ifdef RELEASE
	if (ticks >= REL_TIMER_OFFSET)
		ticks -= REL_TIMER_OFFSET;
#endif
	
#ifdef DEBUG
	if (ticks >= DBG_TIMER_OFFSET)
		ticks -= DBG_TIMER_OFFSET;
#endif

	// Compute the partial TimerA period (16 bit counter) to time.
	LowTicks = ticks & 0xffff;

	// Enforce a minimum partial period to prepare for interrupt.
	LowTicks = (LowTicks >= 5 ? LowTicks : 5);

	// Compute the number of complete TimerA periods.
	gTimer = (ticks >> 16); // Global variable used in TACCR0 ISR.

	// Start the partial TimerA period.  
	TA1CTL &= ~(MC1 + MC0);   // Stop timer.
	TA1CTL = TASSEL1 + ID_3 + TACLR;  // SMCLK/8, no interrupt, clear divider.
	TA1CCR0 = LowTicks; // ~1x10^6 ticks/sec
	TA1CCTL0 = CCIE;          // Compare mode, flag cleared, interrupt enabled.
	TA1CTL |= MC1;            // Start timer in continuous mode.
}

///////////////////////////////////////////////////////////////////////////////
// Function:  WaitTimer
// Purpose:   Wait for a running timer to expire.
// Inputs:    None.
// Outputs:   None.
// Notes:     This function is used with the SetTimer() function.
///////////////////////////////////////////////////////////////////////////////
void WaitTimer(void)
{
	__disable_interrupt();
	
	_NOP(); // Protect next line from interruption.
	
	if (TA1CCTL0 & CCIE) // Timer still running?
	{
		__bis_SR_register(GIE + LPM3_bits);  // Sleep and await interrupt.
		_NOP();
	}
	else // Timer done.
		__enable_interrupt();
}


///////////////////////////////////////////////////////////////////////////////
// Function:  GoSleepVLO
// Purpose:   Puts the microcontroller in very low power mode.
// Inputs:    None.
// Outputs:   None.
// Notes:     VLO oscillator continues to operate.
///////////////////////////////////////////////////////////////////////////////
void goSleepVLO(void)
{
	__bis_SR_register(GIE + LPM3_bits);
	__no_operation();
}


///////////////////////////////////////////////////////////////////////////////
// Function:  GoSleep
// Purpose:   Puts the microcontroller in low power mode.
// Inputs:    None.
// Outputs:   None.
///////////////////////////////////////////////////////////////////////////////
void goSleep(void)
{
	__bis_SR_register(GIE + LPM0_bits);
	__no_operation();
}
